记录后台管理员登录日志

FFIB 2 years ago
parent
commit
b1998d68a0

+ 53 - 11
api/admin_views.py

@@ -20,7 +20,7 @@ from account.models import UserInfo
20 20
 from api.encrypt_views import get_ciphertext
21 21
 from coupon.models import CouponInfo, UserCouponInfo
22 22
 from integral.models import SaleclerkSubmitLogInfo
23
-from logs.models import ComplementCodeLogInfo, MchInfoEncryptLogInfo
23
+from logs.models import ComplementCodeLogInfo, MchInfoEncryptLogInfo, AdministratorLoginLogInfo
24 24
 from mch.models import AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo, ModelInfo
25 25
 from member.models import (GoodsInfo, GoodsOrderInfo, MemberActivityGroupShareInfo, MemberActivityInfo,
26 26
                            MemberActivitySignupInfo)
@@ -1709,7 +1709,7 @@ def administrator_update(request):
1709 1709
     admin_id = request.POST.get('admin_id', '')
1710 1710
 
1711 1711
     target_admin_id = request.POST.get('target_admin_id', '')
1712
-    admin_type = int(request.POST.get('admin_type', 3))
1712
+    admin_type = int(request.POST.get('admin_type', -1))
1713 1713
     phone = request.POST.get('phone', '')
1714 1714
     name = request.POST.get('name', '')
1715 1715
     password = request.POST.get('password', '')
@@ -1725,15 +1725,24 @@ def administrator_update(request):
1725 1725
     if administrator.admin_type != AdministratorInfo.ADMINISTRATOR:
1726 1726
         return response(AdministratorStatusCode.ADMINISTRATOR_PERMISSION_DENIED)
1727 1727
 
1728
-    encryption = make_password(strip(password), settings.MAKE_PASSWORD_SALT, settings.MAKE_PASSWORD_HASHER)
1729
-
1730
-    AdministratorInfo.objects.filter(admin_id=target_admin_id, brand_id=brand_id).update(
1731
-        admin_type=admin_type,
1732
-        phone=phone,
1733
-        name=name,
1734
-        password='',
1735
-        encryption=encryption,
1736
-    )
1728
+    target_admin = AdministratorInfo.objects.get(admin_id=target_admin_id, status=True)
1729
+
1730
+    if admin_type != -1:
1731
+        target_admin.admin_type = admin_type
1732
+    
1733
+    if phone:
1734
+        target_admin.phone = phone
1735
+    
1736
+    if name:
1737
+        target_admin.name = name
1738
+        AdministratorLoginLogInfo.objects.filter(admin_id=target_admin_id).update(admin_name=name)
1739
+
1740
+    
1741
+    if password:
1742
+        encryption = make_password(strip(password), settings.MAKE_PASSWORD_SALT, settings.MAKE_PASSWORD_HASHER)
1743
+        target_admin.encryption = encryption
1744
+    
1745
+    target_admin.save()
1737 1746
 
1738 1747
     return response(200, 'Update Admin Success', u'更新后台管理员成功')
1739 1748
 
@@ -1757,3 +1766,36 @@ def administrator_delete(request):
1757 1766
     AdministratorInfo.objects.filter(admin_id=target_admin_id).update(status=False)
1758 1767
 
1759 1768
     return response(200, 'Delete Admin Success', u'删除后台管理员成功')
1769
+
1770
+
1771
+def administrator_login_list(request):
1772
+    brand_id = request.POST.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
1773
+    admin_id = request.POST.get('admin_id', '')
1774
+    page = request.POST.get('page', 1)
1775
+    num = request.POST.get('num', 20)
1776
+    target_admin_id = request.POST.get('target_admin_id', '')
1777
+
1778
+    if brand_id != settings.KODO_DEFAULT_BRAND_ID:
1779
+        return response(ProductBrandStatusCode.BRAND_NOT_MATCH)
1780
+
1781
+    try:
1782
+        administrator = AdministratorInfo.objects.get(admin_id=admin_id, user_status=AdministratorInfo.ACTIVATED, status=True)
1783
+    except AdministratorInfo.DoesNotExist:
1784
+        return response(AdministratorStatusCode.ADMINISTRATOR_NOT_FOUND)
1785
+
1786
+    if administrator.admin_type != AdministratorInfo.ADMINISTRATOR:
1787
+        return response(AdministratorStatusCode.ADMINISTRATOR_PERMISSION_DENIED)
1788
+
1789
+    logs = AdministratorLoginLogInfo.objects.filter(status=True).order_by('-login_at')
1790
+
1791
+    if target_admin_id:
1792
+        logs = logs.filter(admin_id=target_admin_id)
1793
+
1794
+    count = logs.count()
1795
+    logs, left = pagination(logs, page, num)
1796
+    logs = [log.admindata for log in logs]
1797
+    return response(200, 'Get Administrator Login List Success', u'获取后台管理员登录日志成功', data={
1798
+        'logs': logs,
1799
+        'left': left,
1800
+        'count': count
1801
+    })

+ 10 - 1
api/mch_views.py

@@ -9,6 +9,7 @@ from django.contrib.auth.hashers import check_password
9 9
 from django.db import transaction
10 10
 from django_logit import logit
11 11
 from django_response import response
12
+from ipaddr import client_ip
12 13
 from pywe_miniapp import get_phone_number
13 14
 from pywe_storage import RedisStorage
14 15
 from TimeConvert import TimeConvert as tc
@@ -16,7 +17,7 @@ from TimeConvert import TimeConvert as tc
16 17
 from account.models import UserInfo
17 18
 from coupon.models import CouponInfo, UserCouponInfo
18 19
 from integral.models import SaleclerkSubmitLogInfo
19
-from logs.models import MchInfoEncryptLogInfo
20
+from logs.models import MchInfoEncryptLogInfo, AdministratorLoginLogInfo
20 21
 from mch.models import (ActivityInfo, AdministratorInfo, BrandInfo, ConsumeInfoSubmitLogInfo, DistributorInfo,
21 22
                         LatestAppInfo, LatestAppScreenInfo, ModelInfo, OperatorInfo)
22 23
 from statistic.models import ConsumeModelSaleStatisticInfo, ConsumeSaleStatisticInfo, ConsumeUserStatisticInfo
@@ -78,6 +79,14 @@ def admin_login_api(request):
78 79
     if not check_password(password, administrator.encryption):
79 80
         return response(AdministratorStatusCode.ADMINISTRATOR_PASSWORD_ERROR)
80 81
 
82
+    
83
+    AdministratorLoginLogInfo.objects.create(
84
+        admin_id=administrator.admin_id,
85
+        admin_name=administrator.name,
86
+        login_ip=client_ip(request),
87
+        login_at=tc.utc_datetime(),
88
+    )
89
+
81 90
     request.session['admin_id'] = administrator.admin_id
82 91
 
83 92
     return response(200, 'Admin Login Success', u'管理员登录成功', data={

+ 3 - 0
api/urls.py

@@ -186,6 +186,9 @@ urlpatterns += [
186 186
     url(r'^admin/administrator/create$', admin_views.administrator_create, name='administrator_create'),
187 187
     url(r'^admin/administrator/update$', admin_views.administrator_update, name='administrator_update'),
188 188
     url(r'^admin/administrator/delete$', admin_views.administrator_delete, name='administrator_delete'),
189
+
190
+    url(r'^admin/administrator/login/list$', admin_views.administrator_login_list, name='administrator_login_list'),
191
+
189 192
 ]
190 193
 
191 194
 urlpatterns += [

+ 19 - 0
coupon/migrations/0017_alter_usercouponinfo_coupon_from.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 3.2.9 on 2022-07-04 12:01
3
+
4
+from django.db import migrations, models
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('coupon', '0016_auto_20201202_1203'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='usercouponinfo',
16
+            name='coupon_from',
17
+            field=models.CharField(blank=True, db_index=True, default='MEMBER_BENEFITS', help_text=u'劵来源', max_length=32, null=True, verbose_name='coupon_from'),
18
+        ),
19
+    ]

+ 6 - 1
logs/admin.py

@@ -4,7 +4,7 @@ from django.contrib import admin
4 4
 from django_admin import ReadOnlyModelAdmin
5 5
 
6 6
 from logs.models import (ComplementCodeLogInfo, MchInfoDecryptLogInfo, MchInfoEncryptLogInfo, MchLogInfo,
7
-                         MchSearchModelAndCameraLogInfo)
7
+                         MchSearchModelAndCameraLogInfo, AdministratorLoginLogInfo)
8 8
 
9 9
 
10 10
 class MchInfoEncryptLogInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin):
@@ -32,9 +32,14 @@ class ComplementCodeLogInfoAdmin(admin.ModelAdmin):
32 32
     list_display = ('user_id', 'log_id', 'name', 'phone', 'model_id', 'model_name', 'sn', 'shot_image', 'invoice_image', 'audit_status', 'ciphertext', 'is_contacted', 'is_upload_qiniu', 'status', 'created_at', 'updated_at')
33 33
     list_filter = ('model_id', 'audit_status', 'is_contacted', 'is_upload_qiniu', 'status')
34 34
 
35
+class AdministratorLoginLogInfoAdmin(admin.ModelAdmin):
36
+    list_display = ('admin_id', 'admin_name', 'login_ip', 'login_at', 'status', 'created_at', 'updated_at')
37
+    list_filter = ('admin_id', 'admin_name')
38
+
35 39
 
36 40
 admin.site.register(MchInfoDecryptLogInfo, MchInfoDecryptLogInfoAdmin)
37 41
 admin.site.register(MchInfoEncryptLogInfo, MchInfoEncryptLogInfoAdmin)
38 42
 admin.site.register(MchSearchModelAndCameraLogInfo, MchSearchModelAndCameraLogInfoAdmin)
39 43
 admin.site.register(MchLogInfo, MchLogInfoAdmin)
40 44
 admin.site.register(ComplementCodeLogInfo, ComplementCodeLogInfoAdmin)
45
+admin.site.register(AdministratorLoginLogInfo, AdministratorLoginLogInfoAdmin)

+ 30 - 0
logs/migrations/0018_administratorloginloginfo.py

@@ -0,0 +1,30 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 3.2.9 on 2022-07-04 12:01
3
+
4
+from django.db import migrations, models
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('logs', '0017_complementcodeloginfo_is_upload_qiniu'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='AdministratorLoginLogInfo',
16
+            fields=[
17
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+                ('status', models.BooleanField(default=True, help_text='Status', verbose_name='status')),
19
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
20
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
21
+                ('admin_id', models.CharField(blank=True, help_text='管理员唯一标识', max_length=32, null=True, verbose_name='admin_id')),
22
+                ('admin_name', models.CharField(blank=True, help_text='管理员姓名', max_length=255, null=True, verbose_name='name')),
23
+                ('login_ip', models.CharField(blank=True, help_text='登录IP', max_length=32, null=True, verbose_name='login_ip')),
24
+                ('login_at', models.DateTimeField(blank=True, help_text='登录时间', null=True, verbose_name='login_at')),
25
+            ],
26
+            options={
27
+                'abstract': False,
28
+            },
29
+        ),
30
+    ]

+ 16 - 0
logs/models.py

@@ -193,3 +193,19 @@ class ComplementCodeLogInfo(BaseModelMixin):
193 193
             'ciphertext': self.ciphertext,
194 194
             'created_at': tc.local_string(utc_dt=self.created_at, format='%Y-%m-%d %H:%M:%S')
195 195
         }
196
+
197
+class AdministratorLoginLogInfo(BaseModelMixin):
198
+    admin_id = models.CharField(_(u'admin_id'), max_length=32, blank=True, null=True, help_text=u'管理员唯一标识')
199
+    admin_name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'管理员姓名')
200
+    login_ip = models.CharField(_(u'login_ip'), max_length=32, blank=True, null=True, help_text=_(u'登录IP'))
201
+    login_at = models.DateTimeField(_(u'login_at'), blank=True, null=True, help_text=_(u'登录时间'))
202
+
203
+
204
+    @property
205
+    def admindata(self):
206
+        return {
207
+            'admin_id': self.admin_id,
208
+            'admin_name': self.admin_name,
209
+            'login_ip': self.login_ip,
210
+            'login_at': tc.local_string(utc_dt=self.login_at, format='%Y-%m-%d %H:%M:%S'),
211
+        }

+ 60 - 0
member/migrations/0032_auto_20220704_2001.py

@@ -0,0 +1,60 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 3.2.9 on 2022-07-04 12:01
3
+
4
+from django.db import migrations, models
5
+import simditor.fields
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('member', '0031_auto_20211124_1850'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AlterField(
16
+            model_name='memberactivityinfo',
17
+            name='brand_id',
18
+            field=models.CharField(blank=True, db_index=True, default='', help_text='品牌唯一标识', max_length=32, verbose_name='brand_id'),
19
+        ),
20
+        migrations.AlterField(
21
+            model_name='memberactivityinfo',
22
+            name='brand_name',
23
+            field=models.CharField(blank=True, default='', help_text='品牌名称', max_length=255, verbose_name='brand_name'),
24
+        ),
25
+        migrations.AlterField(
26
+            model_name='memberactivityinfo',
27
+            name='city',
28
+            field=models.CharField(blank=True, default='', help_text='活动城市', max_length=255, verbose_name='city'),
29
+        ),
30
+        migrations.AlterField(
31
+            model_name='memberactivityinfo',
32
+            name='content_rich_text',
33
+            field=simditor.fields.RichTextField(blank=True, default='', help_text='活动描述', verbose_name='content_rich_text'),
34
+        ),
35
+        migrations.AlterField(
36
+            model_name='memberactivityinfo',
37
+            name='location',
38
+            field=models.CharField(blank=True, default='', help_text='活动地点', max_length=255, verbose_name='location'),
39
+        ),
40
+        migrations.AlterField(
41
+            model_name='memberactivityinfo',
42
+            name='share_h5_link',
43
+            field=models.CharField(blank=True, default='', help_text='活动H5分享', max_length=255, verbose_name='share_h5_link'),
44
+        ),
45
+        migrations.AlterField(
46
+            model_name='memberactivityinfo',
47
+            name='share_img_link',
48
+            field=models.CharField(blank=True, default='', help_text='活动图片分享', max_length=255, verbose_name='share_img_link'),
49
+        ),
50
+        migrations.AlterField(
51
+            model_name='memberactivityinfo',
52
+            name='subtitle',
53
+            field=models.CharField(blank=True, default='', help_text='活动二级名称', max_length=255, verbose_name='subtitle'),
54
+        ),
55
+        migrations.AlterField(
56
+            model_name='memberactivityinfo',
57
+            name='title',
58
+            field=models.CharField(blank=True, default='', help_text='活动名称', max_length=255, verbose_name='title'),
59
+        ),
60
+    ]

+ 1 - 1
requirements_dj.txt

@@ -20,7 +20,7 @@ django-redis-connector==1.0.4
20 20
 django-response==1.1.1
21 21
 django-rlog==1.0.7
22 22
 django-shortuuidfield==0.1.3
23
-# django-simpleui==3.9.1
23
+django-simpleui==3.9.1
24 24
 django-six==1.0.4
25 25
 django-uniapi==1.0.10
26 26
 django-we==1.5.6